package com.lagou.handler;

import com.lagou.constant.Constant;
import com.lagou.rpc.RpcRequest;
import com.lagou.rpc.RpcResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.CreateMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;

import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;

public class UserServerHandler extends ChannelInboundHandlerAdapter {
    private static Logger logger = LoggerFactory.getLogger(UserServerHandler.class);

    private ApplicationContext applicationContext;
    private static String serviceNodeName;

    public String getNodeVisitTimeZkPath() {
        return nodeVisitTimeZkPath;
    }

    public void setNodeVisitTimeZkPath(String nodeVisitTimeZkPath) {
        this.nodeVisitTimeZkPath = nodeVisitTimeZkPath;
    }

    private String nodeVisitTimeZkPath;

    public String getServiceNodeName() {
        return serviceNodeName;
    }

    public static void setServiceNodeName(String name) {
        serviceNodeName = name;
    }

    private CuratorFramework curatorFramework;

    public CuratorFramework getCuratorFramework() {
        return curatorFramework;
    }

    public void setCuratorFramework(CuratorFramework curatorFramework) {
        this.curatorFramework = curatorFramework;
    }

    public UserServerHandler(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
        this.curatorFramework = (CuratorFramework)applicationContext.getBean("curatorFramework");
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        Exception exception = null;
        RpcRequest rpcRequest = (RpcRequest) msg;
        Object result = null;
        try {
            String className = rpcRequest.getClassName();
            String methodName = rpcRequest.getMethodName();
            Class clazz = Class.forName(className);

//        需要修改为从spring容器中获取
//        if(className.equals(UserService.class.getName())){
//            className = className + "Impl";
//        }
//        Object obj = clazz.newInstance();
            Object obj = applicationContext.getBean(clazz);

            Method method = clazz.getMethod(methodName, rpcRequest.getParameterTypes());
            result = method.invoke(obj, rpcRequest.getParameters());

            //TODO 将本次访问记录到zookeeper
            updateLateVisitTime();
        } catch (Exception e) {
            exception = e;
            logger.error("调用{}类的{}方法{}时发生错误，参数为{}，错误原因{}", rpcRequest.getClassName(),
                    rpcRequest.getMethodName(), rpcRequest.getParameters(), e.getMessage());
        } finally {
            RpcResponse rpcResponse = new RpcResponse();
            rpcResponse.setCode(exception == null ? 200 : 500);
            rpcResponse.setRequestId(rpcRequest.getRequestId());
            rpcResponse.setException(exception);
            rpcResponse.setResult(result);
            ctx.writeAndFlush(rpcResponse);
        }

        // 判断是否符合约定，符合则调用本地方法，返回数据
        // msg:  UserService#sayHello#are you ok?
//        if(msg.toString().startsWith("UserService")){
//            UserServiceImpl userService = new UserServiceImpl();
//            String result = userService.sayHello(msg.toString().substring(msg.toString().lastIndexOf("#") + 1));
//            ctx.writeAndFlush(result);
//        }


    }

    private void updateLateVisitTime() {
        try {
            String path = Constant.SERVIE_PATH_ZK + "/" + Constant.USER_SERVICE_NAME + "/" + Constant.SERVICE_LAST_VISITED + "/" + Constant.USER_SERVICE_NAME;
            Date date = new Date();
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String visitTime = df.format(date);
            String data = serviceNodeName + "=" + visitTime;
            if(null == nodeVisitTimeZkPath){
                nodeVisitTimeZkPath = curatorFramework.create().creatingParentsIfNeeded().
                        withMode(CreateMode.EPHEMERAL_SEQUENTIAL).
                        forPath(path, data.getBytes());
                logger.info("服务访问时间更新{}成功,返回值{},更新数据{}", Constant.USER_SERVICE_NAME, nodeVisitTimeZkPath, data);
            }else {
                curatorFramework.setData().forPath(nodeVisitTimeZkPath,data.getBytes());
                logger.info("服务访问时间更新{}成功,节点路径{},更新数据{}", Constant.USER_SERVICE_NAME, nodeVisitTimeZkPath, data);
            }
        } catch (Exception e) {
            logger.error("服务访问时间更新{}失败", Constant.USER_SERVICE_NAME, e);
        }
    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }
}
